#include "KRTSOperator.h"

#include <string_view>
#include <stdexcept>
#include <format>
#include <iostream>

#include "../Common/Common.h"
#include "../../TestKernel/SharedData.h"

constexpr std::string_view KRTS_DRIVER_NAME{"070075"};

KRTSOperator::KRTSOperator() {
    // 1.打开驱动
    KSError ksError = KS_openDriver(KRTS_DRIVER_NAME.data());
    if (ksError != KS_OK) {
        throw std::runtime_error(
            std::format("KRTSOperator: KS_openDriver failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 2.创建共享内存
    ksError = KS_createSharedMemEx(
        &shared_data_handle,
        "",
        sizeof(SharedData),
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            std::format("KRTSOperator: KS_createSharedMemEx failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 3. 获取共享内存
    ksError = KS_getSharedMemEx(
        shared_data_handle,
        (void **)&shared_data,
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            std::format("KRTSOperator: KS_getSharedMemEx failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
}

KRTSOperator::~KRTSOperator() {
    // 1. 释放共享内存
    KSError ksError;
    if (shared_data_handle) {
        ksError = KS_freeSharedMemEx(shared_data_handle, KSF_NO_FLAGS);
        // 2. 关闭驱动
        KS_closeDriver();
    }
    std::cout << "KRTS end" << std::endl;

}

void KRTSOperator::Start() {
    if (!shared_data) {
        throw std::runtime_error("KRTSOperator: shared_data is null");
    }
    // 1.加载内核dll
    KSError ksError = KS_loadLibraryKernel(
        &shared_data->kernel_handle,
        "TestKernel.dll",
        nullptr,
        nullptr,
        KSF_KERNEL_EXEC);
    if (ksError != KS_OK) {
        throw std::runtime_error(
            std::format("KRTSOperator: KS_loadLibraryKernel failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 2.枚举和打开网卡
    char device_name[256];
    CommonOperator::OutputTxt("Following network adapters found:");
    for (int i = 0; i < 10; i++) {
        ksError = KS_enumDevices(
            "NET",
            i,
            device_name,
            KSF_NO_FLAGS);
        if (ksError != KS_OK) {
            if (KSERROR_CODE(ksError) != KSERROR_DEVICE_NOT_FOUND) {
                std::cout << "Unable to query network device name!\n";
            }
            if (KSERROR_CODE(ksError) == KSERROR_DEVICE_NOT_FOUND && !i) {
                std::cout << "No network adapters found\n";
                KS_closeDriver();
                return;
            }
            break;
        }
        CommonOperator::OutputDec(i, "", ": ", false);
        CommonOperator::OutputTxt(device_name);
    }
    std::cout << R"(
Attention!
By selecting a device its Windows driver gets removed and replaced by the
appropriate Kithara driver. This will render the network device for the duration
of this sample invisible to Windows.
Be sure that all other Applications using that device are closed right now!)"<< std::endl;
    int device_index = CommonOperator::inputDec("Device number: ", 0);
    ksError = KS_enumDevices(
        "NET",
        device_index,
        device_name,
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            std::format("KRTSOperator: KS_enumDevices failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    ksError = KS_openNetworkAdapter(
        &shared_data->adapter_handle,          // 网卡句柄
        device_name,                              // 网卡名字
        nullptr,                                  // 网卡配置
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            std::format("open network adapter failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 3.创建主站
    char* pXmlPath = CommonOperator::inputTxt(
        "Please enter config path to XML files: ",
        "E:\\program\\kithara\\Kithara_LinkControl__Demo\\Kithara_Axis_Test_Demo\\xml");
    ksError = KS_createEcatMaster(
        &shared_data->master_handle,
        shared_data->adapter_handle,
        pXmlPath,
        "",
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            std::format("KRTSOperator: KS_createEcatMaster failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 4.执行内核初始化
    ksError = KS_execKernelFunctionEx(
        shared_data->kernel_handle,
        "InitFuction",
        shared_data_handle,
        NULL,
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        throw std::runtime_error(
            format("KRTSOperator: KS_execKernelFunctionEx failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
}

void KRTSOperator::Run() {
    CommonOperator::OutputTxt(" ");
    CommonOperator::OutputTxt("Press [Q] to finish the process data exchange,");
    CommonOperator::OutputTxt("Press [E] to enable");
    CommonOperator::OutputTxt("Press [F] to run faster");
    CommonOperator::OutputTxt("Press [S] to run slower");
    CommonOperator::OutputTxt("Press [H] to go home");
    CommonOperator::OutputTxt(" ");

    bool exitSample = false;
    while (!exitSample) {
        CommonOperator::waitTime(100 * ms);
        CommonOperator::OutputTxt("\r", false);
        //for(int i = 0; i < Total_Axis_Num; i++) {
            CommonOperator::OutputDec(shared_data->command_position[0], "command_position:", " ", false);
            CommonOperator::OutputDec(shared_data->actual_position[0], "actual_position:", " ", false);
            CommonOperator::OutputHex04(shared_data->statues[0], "statues:0x", " ", false);
            CommonOperator::OutputHex04(shared_data->control_words[0], "control_words:0x", " ", false);
        //}
        if (shared_data->error != KS_OK) {
            break;
        }
        if (!myKbhit())
            continue;
        bool write = false;
        int key = myGetch();
        switch (key) {
            case 'q':
            case 'Q':
            exitSample = true;
            break;
            case 'F':
            case 'f':

            break;
            case 'E':
            case 'e':
                std::cout << "-----------Enable Command------------------" << std::endl;
                shared_data->command_type = 1;
            break;
            case 'D':
            case 'd':
                std::cout << "-----------Disable Command------------------" << std::endl;
                shared_data->command_type = 2;
            break;
            case 'T':
            case 't':
                std::cout << "-----------Enable Command------------------" << std::endl;
            break;
            case 'S':
            case 's':

            break;
            case 'H':
            case 'h':
                std::cout << "-----------Home Command------------------" << std::endl;
                // int device_index = CommonOperator::inputDec("Device number: ", 0);
                shared_data->command_type = 3;
            break;
            case 'C':
            case 'c':
                std::cout << "-----------Home Cancel Command------------------" << std::endl;
                // int device_index = CommonOperator::inputDec("Device number: ", 0);
                shared_data->command_type = 4;
            break;
            default:
            continue;
        }
    }
    CommonOperator::OutputTxt(" ");
}

void KRTSOperator::Stop() {
    // 1. 执行内核退出函数
    KSError ksError = KS_execKernelFunctionEx(
        shared_data->kernel_handle,
        "ExitFuction",
        shared_data_handle,
        NULL,
        KSF_NO_FLAGS);
    if (ksError != KS_OK) {
        KS_closeDriver();
        throw std::runtime_error(
            format("KRTSOperator: KS_execKernelFunctionEx failed, error: {}",
            CommonOperator::GetErrorStr(ksError)));
    }
    // 卸载内核
    if (!shared_data->kernel_handle) {

        ksError = KS_freeKernel(shared_data->kernel_handle);
        if (ksError != KS_OK) {
            throw std::runtime_error(
                format("KRTSOperator: KS_freeKernel failed, error: {}",
                CommonOperator::GetErrorStr(ksError)));
        }
    }
}
